package com.example.util.encryption;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 加签验签,私钥加签,公钥验签
 * 加密解密,公钥加密,私钥解密/私钥加密,公钥解密
 *
 * @author wangkai
 */
public class Sha1withRSAUtil {

    public static final String KEY_ALGORITHM = "RSA";
    public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
    public static final String CHARSET_NAME = "UTF-8";

    /**
     * 加签
     *
     * @param privateKey
     * @param content
     * @return
     */
    public static String sign(String privateKey, String content) {
        try {
            PrivateKey priKey = getPrivateKey(privateKey);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initSign(priKey);
            signature.update(content.getBytes(CHARSET_NAME));
            return EncryptionUtil.encryptBASE64(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 验证签名
     *
     * @param signString 私钥签名
     * @param sign       验证数据
     * @return
     * @throws Exception
     */
    public static boolean verify(String public_key, String signString, String sign) throws Exception {
        byte[] data = EncryptionUtil.decryptBASE64(signString);
        byte[] signs = sign.getBytes(CHARSET_NAME);
        try {
            PublicKey pubKey = getPublicKey(public_key);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(pubKey);
            signature.update(signs);
            return signature.verify(data);
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 私钥加密数据
     *
     * @param originData
     * @return
     */
    public static String encodeDataPrivateKey(String private_key, String originData) {
        try {
            // 取私钥对象
            PrivateKey priKey = getPrivateKey(private_key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, priKey);
            byte[] bytesEncrypt = cipher.doFinal(originData.getBytes(CHARSET_NAME));
            //Base64编码
//            byte[] bytesEncryptBase64 =  Base64.getEncoder().encode(bytesEncrypt);
//            return new String(bytesEncryptBase64);
            return EncryptionUtil.encryptBASE64(bytesEncrypt);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥加密数据
     *
     * @param public_key
     * @param originData
     * @return
     */
    public static String encodeDataPublicKey(String public_key, String originData) {
        try {
            // 取公钥对象
            PublicKey pubKey = getPublicKey(public_key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] bytesEncrypt = cipher.doFinal(originData.getBytes(CHARSET_NAME));
            //Base64编码
//            byte[] bytesEncryptBase64 = Base64.getEncoder().encode(bytesEncrypt);
//            return new String(bytesEncryptBase64);
            return EncryptionUtil.encryptBASE64(bytesEncrypt);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥解密数据
     *
     * @param encodeData
     * @return
     */
    public static String decodeDataPrivateKey(String private_key, String encodeData) {
        try {
            // 取私钥对象
            PrivateKey privateKey = getPrivateKey(private_key);
            //Base64解码
//            byte[] bytesEncrypt = Base64.getDecoder().decode(encodeData);
            byte[] bytesEncrypt = EncryptionUtil.decryptBASE64(encodeData);
            //加密
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] bytesDecrypt = cipher.doFinal(bytesEncrypt);
            return new String(bytesDecrypt);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥解密数据
     *
     * @param encodeData
     * @return
     */
    public static String decodeDataPublicKey(String public_key, String encodeData) {
        try {
            // 取公钥对象
            PublicKey publicKey = getPublicKey(public_key);
            //Base64解码
//            byte[] bytesEncrypt = Base64.getDecoder().decode(encodeData);
            byte[] bytesEncrypt = EncryptionUtil.decryptBASE64(encodeData);
            //加密
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] bytesDecrypt = cipher.doFinal(bytesEncrypt);
            return new String(bytesDecrypt);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 将字符串转换成公钥
     *
     * @param key
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes = EncryptionUtil.decryptBASE64(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 将字符串转换成私钥
     *
     * @param key
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes = EncryptionUtil.decryptBASE64(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }


    /**
     * 获取文件私钥
     *
     * @param path
     * @return
     */
    public static String getPathPrivateKey(String path) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(path));
            String s = br.readLine();
            StringBuffer privatekey = new StringBuffer();
            s = br.readLine();
            while (s.charAt(0) != '-') {
                privatekey.append(s + "\r");
                s = br.readLine();
            }
            return privatekey.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 获取文件公钥
     *
     * @param path
     * @return
     */
    public static String getPathPublicKey(String path) {
        try {
            return getPathPrivateKey(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


//    public static void main(String[] args) {
//        String privateKeyPath = "F:\\规划项目\\spring.startup\\src\\main\\resources\\rsa_private_key.pem";
//        String publicKeyPath = "F:\\规划项目\\spring.startup\\src\\main\\resources\\rsa_public_key.pem";
//        String jiami = encodeDataPublicKey(getPathPublicKey(publicKeyPath), "食之无味,弃之可惜");
//        System.out.println("加密后的数据:" + jiami);
//        String jiemi = decodeDataPrivateKey(getPathPrivateKey(privateKeyPath), jiami);
//        System.out.println("解密后的数据:" + jiemi);
//    }

//    public static void main(String[] args) {
//
//        String privateKeyPath = "F:\\规划项目\\spring.startup\\src\\main\\resources\\rsa_private_key.pem";
//        String publicKeyPath = "F:\\规划项目\\spring.startup\\src\\main\\resources\\rsa_public_key.pem";
//
//        /**
//         * 私钥加签
//         * 公钥验签
//         */
//        try {
//            String sign = "食之无味,弃之可惜";
////            String sign = "memberid=1232&changAmount=123&changeWay=1";
//            String signString = sign(getPathPrivateKey(privateKeyPath), sign);
//            System.out.println("加签的数据:" + signString);
//            boolean flag = verify(getPathPublicKey(publicKeyPath), signString, sign);
//            System.out.println("验证结果:" + flag);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
}